#pragma once

#include <iostream>
#include <functional>
#include <thread>
#include <string>
#include <cstring>
#include <cstdlib>
#include <memory>
#include "sock_tcp.hpp"
#include "error.hpp"
#include "task.hpp"
#include "pthreadPool.hpp"
#include "log.hpp"
#include <signal.h>

class ServerTCP;
class ThreadData
{
public:
    int _newsockfd;
    std::string _ip;
    uint16_t _port;
    ServerTCP *_server;

public:
    ThreadData(int newsockfd, const std::string &ip, const uint16_t &port, ServerTCP *server = nullptr)
        : _newsockfd(newsockfd), _ip(ip), _port(port), _server(server)
    {
    }
    ~ThreadData() {}
};

class ServerTCP
{
private:
    using func_t = std::function<std::string(const std::string &)>;
    const static uint16_t defaultPort = 8888;
    friend class ThreadData;

public:
    ServerTCP(func_t func = nullptr, uint16_t port = defaultPort)
        : _port(port), _func(func)
    {
    }
    ~ServerTCP() {}

    void Init()
    {
        _listenSock.Socket();
        _listenSock.Bind(_port);
        _listenSock.Listen();
    }

    void Start()
    {
        // 忽略子进程退出信号
        signal(SIGCHLD, SIG_IGN);
        while (true)
        {
            // 1. accept
            std::string ip;
            uint16_t port;
            int newsockfd = _listenSock.Accept(&ip, &port);
            // 2. 将newsockfd交给新线程处理，进行相关的服务
            Task task(std::bind(&ServerTCP::Server, this, std::placeholders::_1, std::placeholders::_2,
                                std::placeholders::_3),
                      newsockfd, ip, port);
            ThreadPool<Task>::getInstance()->pushTask(task);
        }
    }

private:
    void Server(int newsockfd, const std::string &ip, const uint16_t &port)
    {
        while (true)
        {
            // 2. recv
            std::string recvStr = _listenSock.Recv(newsockfd);
            if (recvStr == "")
            {
                logMessage(Info, "[client %s:%d] quit!", ip.c_str(), port);
                break;
            }
            logMessage(Info, "[client %s:%d] says # %s", ip.c_str(), port, recvStr.c_str());
            // 3. send
            std::string sendStr = _func(recvStr);
            _listenSock.Send(newsockfd, sendStr);
        }
        // 4. close
        close(newsockfd);
    }

private:
    SockTCP _listenSock;
    uint16_t _port;
    func_t _func;
};